package com.service.admin.base.service.impl;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.service.admin.base.controller.rep.WalletConfigRep;
import com.service.admin.base.controller.rep.WalletPoolPageRep;
import com.service.admin.base.controller.rep.WalletServerRep;
import com.service.admin.base.controller.req.WalletConfigReq;
import com.service.admin.base.controller.req.WalletPoolPageReq;
import com.service.admin.base.controller.req.WalletPoolReq;
import com.service.admin.base.service.WalletPoolService;
import com.service.admin.support.TronProperty;
import com.service.core.exception.CommonException;
import com.service.core.rest.request.PageRequest;
import com.service.core.rest.response.CommonPageRep;
import com.service.dao.enums.CoinsEnum;
import com.service.dao.enums.WalletConfigEnum;
import com.service.dao.enums.WalletEnums;
import com.service.dao.mapper.CoinsMapper;
import com.service.dao.mapper.WalletConfigMapper;
import com.service.dao.mapper.WalletPoolMapper;
import com.service.dao.model.Coins;
import com.service.dao.model.WalletConfig;
import com.service.dao.model.WalletPool;
import com.service.admin.upload.controller.req.WalletPoolUpLoadReq;
import com.service.utility.modelmapper.ModelMapperUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class WalletPoolServiceImpl extends ServiceImpl<WalletPoolMapper, WalletPool> implements WalletPoolService {

    @Autowired
    private CoinsMapper coinsMapper;

    @Autowired
    private WalletConfigMapper walletConfigMapper;

    @Autowired
    private TronProperty tronProperty;

    @Override
    @Transactional
    public void importFromExcel(Integer coinsId, List<WalletPoolUpLoadReq> walletPoolUpLoadReqs) {
        Coins coins = coinsMapper.selectById(coinsId);

        if (ObjectUtils.isEmpty(coins)) {
            throw new CommonException("导入钱包池失败,导入货币不存在");
        }

        for (WalletPoolUpLoadReq walletPoolUpLoadReq : walletPoolUpLoadReqs) {
            WalletPool walletPool = ModelMapperUtil.getStrictModelMapper().map(walletPoolUpLoadReq, WalletPool.class);
            walletPool.setWalletType(WalletEnums.Type.valueOf(walletPoolUpLoadReq.getType().toUpperCase()).getCode());
            walletPool.setCoinsName(coins.getCoinName());
            walletPool.setAddrStatus(WalletEnums.Status.ACTIVE.getCode());
            walletPool.setCoinsId(coinsId);
            if(!ObjectUtils.isEmpty(getOne(new QueryWrapper<WalletPool>().lambda()
                    .eq(WalletPool::getAddr, walletPoolUpLoadReq.getAddr()).last("limit 1")))){
                throw new CommonException(walletPoolUpLoadReq.getAddr()+"地址已存在");
            }
            save(walletPool);
        }
    }

    @Override
    public CommonPageRep<WalletPoolPageRep> page(WalletPoolPageReq pageReq) {
        Page<WalletPool> page = PageHelper.startPage(pageReq.getPageNo(), pageReq.getPageSize());

        LambdaQueryWrapper<WalletPool> wrapper = new QueryWrapper<WalletPool>().lambda();
        //有地址条件，直接过滤地址，其它条件忽略
        if(StringUtils.isNotBlank(pageReq.getAddress())){
            wrapper.eq(WalletPool::getAddr,pageReq.getAddress());
        }else{
            if(!ObjectUtils.nullSafeEquals(pageReq.getWalletType(),WalletEnums.Type.ALL)){
                wrapper.eq(WalletPool::getWalletType, pageReq.getWalletType().getCode());
            }
            wrapper.eq(WalletPool::getCoinsId, pageReq.getCoins().getCode())
                    .eq(WalletPool::getAddrStatus, pageReq.getStatus().getCode());
        }
        list(wrapper);
        List<WalletPoolPageRep> resultList = page.getResult().stream().map(item -> ModelMapperUtil.getStrictModelMapper().map(item, WalletPoolPageRep.class)).collect(Collectors.toList());
        return CommonPageRep.buildResultRep(page, resultList);
    }

    @Override
    public CommonPageRep<WalletConfigRep> configList(PageRequest pageReq) {
        Page<WalletConfig> page = PageHelper.startPage(pageReq.getPageNo(), pageReq.getPageSize());
        walletConfigMapper.selectList(new QueryWrapper<WalletConfig>().lambda());
        List<WalletConfigRep> resultList = page.getResult().stream().map(item -> ModelMapperUtil.getStrictModelMapper().map(item,WalletConfigRep.class)).collect(Collectors.toList());
        return CommonPageRep.buildResultRep(page,resultList);
    }

    @Override
    public void generateWallets(WalletPoolReq walletPoolReq) {
        if(ObjectUtils.nullSafeEquals(walletPoolReq.getWalletType(),WalletEnums.Type.TRC20)){
            String url = tronProperty.getServerUrl();
            String result = HttpUtil.get(url+"/api/wallet/generate?num="+walletPoolReq.getNumber());
            log.info("生成钱包接口，generateWallets request {}",result);
            try{
                WalletServerRep walletServerRep = JSONObject.parseObject(result, WalletServerRep.class);
                if(!ObjectUtils.nullSafeEquals(walletServerRep.getCode(), HttpStatus.OK.value())){
                    throw new CommonException("生成钱包失败！接口消息："+walletServerRep.getMsg());
                }
            }catch (Exception e){
                throw new CommonException("生成钱包失败！接口消息："+e.getMessage());
            }
        }
    }

    @Override
    public void initWalletConfig(WalletConfigReq walletConfigReq){
        WalletConfig walletConfig = walletConfigMapper.selectOne(new QueryWrapper<WalletConfig>().lambda().eq(
                WalletConfig::getCoin,walletConfigReq.getType().getName())
        );
        if(!ObjectUtils.isEmpty(walletConfig)){
            walletConfig.setCoinbase(walletConfigReq.getAddr());
            walletConfig.setPrivateKey(walletConfigReq.getPk());
            walletConfigMapper.updateById(walletConfig);
        } else {
            walletConfig = WalletConfig.builder().coin(walletConfigReq.getType().getName())
                    .contract(walletConfigReq.getAddr())
                    .decimals(walletConfigReq.getDecimal())
                    .privateKey(walletConfigReq.getPk()).build();
            walletConfigMapper.insert(walletConfig);
        }
    }
}
